package demo8

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

/*
	无缓冲的通道
		1.  这种类型的通道要求发送 goroutine 和接收 goroutine 同时准备好，才能完成发送和接收操作
		2.  如果两个 goroutine 没有同时准备好，通道会导致先执行发送或接收操作的 goroutine 阻塞等待。
		3.  这种对通道进行发送和接收的交互行为本身就是同步的。
*/

// wg 用来等待程序结束, GoRoutine 的计数器
var wg sync.WaitGroup

// 初始化函数
func init() {
	rand.Seed(time.Now().UnixNano())
}

// player 模拟一个选手在打网球
func player(name string, court chan int) {
	// 在函数退出时调用Done 来通知main 函数工作已经完成
	defer wg.Done()

	for {
		// 等待球被打进来， channel 接受参数
		ball, ok := <-court

		// 通道被关闭，则获取胜利
		if !ok {
			fmt.Printf("player %s Won\n", name)
			return
		}

		// 选随机数，然后用这个数来判断我们是否丢球
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("Player %s Missed %d\n", name, n)

			// 关闭通道，表示当前选手输了
			close(court)
			return
		}

		// 显示击球数，并将击球数加 1
		fmt.Printf("Player %s Hit %d\n", name, ball)
		ball++

		// 将球击打回去, channel 发送值
		court <- ball
	}
}

// TestDemo87 无缓冲的通道
func TestDemo87() {
	// 创建一个无缓冲的通道, 让两个 goroutine 在击球时能够互相同步
	court := make(chan int)

	// 计数器加 2，表示等待 2 个 goroutine
	wg.Add(2)

	// 启动两个 goroutine, 代表两个选手
	go player("Loda", court)
	go player("Th000", court)

	// 发球
	court <- 1

	// 等待游戏结束, 利用 wg 的 Wait() 和 Done() 决定 channel 的 完成状态
	wg.Wait()
}
